#include "includes.h"
#include "tr_media_sys.h"
#include "sys_impl.h"
#include "vdec_impl.h"
#include "vpss_impl.h"
#include "vo_impl.h"

#include "mpp_allocator.h"
#include "os_allocator.h"

typedef struct trMEM_ALLOCATOR_S {
    MppAllocator allocator;
    MppAllocatorApi *api;
} MEM_ALLOCATOR_S;

static MEM_ALLOCATOR_S g_MemAllocator = {0};

extern MPP_VDEC_S g_vdec_devices[];
extern MPP_VPSS_GROUP_S *g_stVpssGroups[];
extern MPP_VO_VIDEO_LAYER_S g_stVideoLayers[];

HI_S32 HI_MPI_SYS_Init()
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_Exit()
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_SetConf(const MPP_SYS_CONF_S *pstSysConf)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_GetConf(MPP_SYS_CONF_S *pstSysConf)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_Bind(MPP_CHN_S *pstSrcChn, MPP_CHN_S *pstDestChn)
{
    int32_t s32SrcType;
    int32_t s32DstType;
    PIN_S *pstSrcPin;
    PIN_S *pstDstPin;

    s32SrcType = pstSrcChn->enModId;
    s32DstType = pstDestChn->enModId;

    switch (s32SrcType)
    {
        case HI_ID_VDEC:
        {
            assert(pstSrcChn->s32DevId == 0);
            pstSrcPin = &g_vdec_devices[pstSrcChn->s32DevId].stPinData.pstOutPins[pstSrcChn->s32ChnId];
            break;
        }
        case HI_ID_VPSS:
        {
            pstSrcPin = &g_stVpssGroups[pstSrcChn->s32DevId]->stPinData.pstOutPins[pstSrcChn->s32ChnId];
            break;
        }
        case HI_ID_VOU:
        {
            pstSrcPin = &g_stVideoLayers[pstSrcChn->s32DevId].stPinData.pstOutPins[pstSrcChn->s32ChnId];
            break;
        }
        default:
        {
            LOG_ERR("unkown module type %d.\n", s32SrcType);
            return HI_FAILURE;
        }
    }

    switch (s32DstType)
    {
        case HI_ID_VPSS:
        {
            pstDstPin = &g_stVpssGroups[pstDestChn->s32DevId]->stPinData.pstInPins[pstDestChn->s32ChnId];
            break;
        }
        case HI_ID_VOU:
        {
            pstDstPin = &g_stVideoLayers[pstDestChn->s32DevId].stPinData.pstInPins[pstDestChn->s32ChnId];
            break;
        }
        default:
        {
            LOG_ERR("unkown module type %d.\n", s32DstType);
            return HI_FAILURE;
        }
    }

    pstSrcPin->bConnect = TRUE;
    pstSrcPin->stInfo = *pstDestChn;

    pstDstPin->bConnect = TRUE;
    pstDstPin->stInfo = *pstSrcChn;

    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_UnBind(MPP_CHN_S *pstSrcChn, MPP_CHN_S *pstDestChn)
{
    int32_t s32SrcType;
    int32_t s32DstType;
    PIN_S *pstSrcPin;
    PIN_S *pstDstPin;

    s32SrcType = pstSrcChn->enModId;
    s32DstType = pstDestChn->enModId;

    switch (s32SrcType)
    {
        case HI_ID_VDEC:
        {
            assert(pstSrcChn->s32DevId == 0);
            pstSrcPin = &g_vdec_devices[pstSrcChn->s32DevId].stPinData.pstOutPins[pstSrcChn->s32ChnId];
            break;
        }
        case HI_ID_VPSS:
        {
            pstSrcPin = &g_stVpssGroups[pstSrcChn->s32DevId]->stPinData.pstOutPins[pstSrcChn->s32ChnId];
            break;
        }
        case HI_ID_VOU:
        {
            pstSrcPin = &g_stVideoLayers[pstSrcChn->s32DevId].stPinData.pstOutPins[pstSrcChn->s32ChnId];
            break;
        }
        default:
        {
            LOG_ERR("unkown module type %d.\n", s32SrcType);
            return HI_FAILURE;
        }
    }

    switch (s32DstType)
    {
        case HI_ID_VPSS:
        {
            pstDstPin = &g_stVpssGroups[pstDestChn->s32DevId]->stPinData.pstInPins[pstDestChn->s32ChnId];
            break;
        }
        case HI_ID_VOU:
        {
            pstDstPin = &g_stVideoLayers[pstDestChn->s32DevId].stPinData.pstInPins[pstDestChn->s32ChnId];
            break;
        }
        default:
        {
            LOG_ERR("unkown module type %d.\n", s32DstType);
            return HI_FAILURE;
        }
    }

    pstSrcPin->bConnect = FALSE;
    memset(&pstSrcPin->stInfo, 0L, sizeof(MPP_CHN_S));
    pstSrcPin->stInfo.enModId = HI_ID_BUTT;

    pstDstPin->bConnect = FALSE;
    memset(&pstDstPin->stInfo, 0L, sizeof(MPP_CHN_S));
    pstDstPin->stInfo.enModId = HI_ID_BUTT;

    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_GetBindbyDest(MPP_CHN_S *pstDestChn, MPP_CHN_S *pstSrcChn)
{
    int32_t s32DstType;
    PIN_S *pstDstPin;

    if (pstSrcChn == NULL ||  pstDestChn == NULL || pstDestChn->enModId == HI_ID_BUTT)
        return HI_FAILURE;

    s32DstType = pstDestChn->enModId;

    switch (s32DstType)
    {
        case HI_ID_VPSS:
        {
            pstDstPin = &g_stVpssGroups[pstDestChn->s32DevId]->stPinData.pstInPins[pstDestChn->s32ChnId];
            break;
        }
        case HI_ID_VOU:
        {
            pstDstPin = &g_stVideoLayers[pstDestChn->s32DevId].stPinData.pstInPins[pstDestChn->s32ChnId];
            break;
        }
        default:
        {
            LOG_ERR("unkown module type %d.\n", s32DstType);
            return HI_FAILURE;
        }
    }

    if (!pstDstPin->bConnect)
        return HI_FAILURE;

    *pstSrcChn = pstDstPin->stInfo;

    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_GetVersion(MPP_VERSION_S *pstVersion)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_GetCurPts(HI_U64 *pu64CurPts)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_InitPtsBase(HI_U64 u64PtsBase)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_SyncPts(HI_U64 u64PtsBase)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_MmzFree(HI_U32 u32PhyAddr, HI_VOID *pVirtAddr)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_MmzFlushCache(HI_U32 u32PhyAddr, HI_VOID *pVitAddr, HI_U32 u32Size)
{
    return HI_SUCCESS;
}

HI_VOID * HI_MPI_SYS_Mmap(HI_U32 u32PhyAddr, HI_U32 u32Size)
{
    return HI_SUCCESS;
}

HI_VOID* HI_MPI_SYS_MmapCache(HI_U32 u32PhyAddr, HI_U32 u32Size)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_Munmap(HI_VOID* pVirAddr, HI_U32 u32Size)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_MflushCache(HI_U32 u32PhyAddr, HI_VOID *pVirAddr, HI_U32 u32Size)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_SetReg(HI_U32 u32Addr, HI_U32 u32Value)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_GetReg(HI_U32 u32Addr, HI_U32 *pu32Value)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_SetMemConf(MPP_CHN_S *pstMppChn,const HI_CHAR *pcMmzName)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_GetMemConf(MPP_CHN_S *pstMppChn,HI_CHAR *pcMmzName)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_CloseFd(HI_VOID)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_SetScaleCoefLevel(SCALE_RANGE_S *pstScaleRange,SCALE_COEFF_LEVEL_S *pstScaleCoeffLevel)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_GetScaleCoefLevel(SCALE_RANGE_S *pstScaleRange,SCALE_COEFF_LEVEL_S *pstScaleCoeffLevel)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_GetCustomCode(HI_U32 *pu32CustomCode)
{
    return HI_SUCCESS;
}

HI_S32 HI_MPI_SYS_GetChipId(HI_U32 *pu32ChipId)
{
    return HI_SUCCESS;
}

int32_t HI_MPI_SYS_PIN_DATA_Init_I(PIN_DATA_S *pstPinDat, int32_t s32MaxInput, int32_t s32MaxOutput)
{
    if (pstPinDat == NULL || s32MaxInput < 0 || s32MaxOutput < 0)
        return HI_FAILURE;

    pstPinDat->pstInPins = (PIN_S *)calloc(s32MaxInput, sizeof(PIN_S));
    pstPinDat->pstOutPins = (PIN_S *)calloc(s32MaxOutput, sizeof(PIN_S));

    pstPinDat->s32InPinMaxNum = s32MaxInput;
    pstPinDat->s32OutPinMaxNum = s32MaxOutput;

    return HI_SUCCESS;
}

int32_t HI_MPI_SYS_PIN_DATA_DeInit_I(PIN_DATA_S *pstPinDat)
{
    if (pstPinDat == NULL)
        return HI_FAILURE;

    if (pstPinDat->pstInPins)
    {
        free(pstPinDat->pstInPins);
        pstPinDat->pstInPins = NULL;
    }

    if (pstPinDat->pstOutPins)
    {
        free(pstPinDat->pstOutPins);
        pstPinDat->pstOutPins = NULL;
    }

    return HI_SUCCESS;
}

int32_t HI_MPI_SYS_Get_Channel_Image_Info(MPP_CHN_S *pstChn, MPP_CHANNEL_IMG_INFO_S *pstImgInfo)
{
    int32_t s32ModType;
    PIN_S *pstPin;

    s32ModType = pstChn->enModId;

    switch (s32ModType)
    {
        case HI_ID_VDEC:
        {
            pstImgInfo->u32Width = g_vdec_devices[pstChn->s32DevId].pstChannels[pstChn->s32ChnId].u32Width;
            pstImgInfo->u32Height = g_vdec_devices[pstChn->s32DevId].pstChannels[pstChn->s32ChnId].u32Height;
            pstImgInfo->enPixelFormat = g_vdec_devices[pstChn->s32DevId].pstChannels[pstChn->s32ChnId].enPixelFormat;
            pstImgInfo->stFrameRate = g_vdec_devices[pstChn->s32DevId].pstChannels[pstChn->s32ChnId].stFrameRate;
            break;
        }
        case HI_ID_VPSS:
        {
            pstImgInfo->u32Width = g_stVpssGroups[pstChn->s32DevId]->pstChannels[pstChn->s32ChnId].u32Width;
            pstImgInfo->u32Height = g_stVpssGroups[pstChn->s32DevId]->pstChannels[pstChn->s32ChnId].u32Height;
            pstImgInfo->enPixelFormat = g_stVpssGroups[pstChn->s32DevId]->pstChannels[pstChn->s32ChnId].enPixelFormat;
            pstImgInfo->stFrameRate = g_stVpssGroups[pstChn->s32DevId]->pstChannels[pstChn->s32ChnId].stFrameRate;

            break;
        }
        case HI_ID_VOU:
        {
            pstImgInfo->u32Width = g_stVideoLayers[pstChn->s32DevId].pstChannels[pstChn->s32ChnId].stRect.u32Width;
            pstImgInfo->u32Height = g_stVideoLayers[pstChn->s32DevId].pstChannels[pstChn->s32ChnId].stRect.u32Height;
            pstImgInfo->enPixelFormat = g_stVideoLayers[pstChn->s32DevId].enPixelFormat;
            //pstImgInfo->stFrameRate = g_stVideoLayers[pstChn->s32DevId].pstChannels[pstChn->s32ChnId].u32FrameRate;

            break;
        }
        default:
        {
            LOG_ERR("unkown module type %d.\n", s32ModType);
            return HI_FAILURE;
        }
    }

    return HI_SUCCESS;
}

static int32_t MEM_ALLOCATOR_Init()
{
    int32_t ret = 0;
    ret = mpp_allocator_get(&g_MemAllocator.allocator, &g_MemAllocator.api, MPP_BUFFER_TYPE_DRM);
    return ret;
}

static int32_t MEM_ALLOCATOR_DeInit()
{
    int32_t ret = 0;
    ret = mpp_allocator_put(&g_MemAllocator.allocator);
    return ret;
}

int32_t HI_MPI_SYS_HardWareMemAlloc(uint32_t *pu32DrmFd, uint32_t *pu32PhyAddr, void **ppVirtAddr, uint32_t u32Len)
{
    int32_t ret = 0;
    MppBufferInfo bufferInfo = {0};

    bufferInfo.type = MPP_BUFFER_TYPE_DRM;
    bufferInfo.size = (size_t)u32Len;

    ret = g_MemAllocator.api->alloc(g_MemAllocator.allocator, &bufferInfo);
    if (ret == MPP_OK)
    {
        g_MemAllocator.api->mmap(g_MemAllocator.allocator, &bufferInfo);
        *pu32DrmFd = bufferInfo.fd;
        *ppVirtAddr = bufferInfo.ptr;
    }

    return ret;
}

int32_t HI_MPI_SYS_HardWareMemFree(uint32_t u32DrmFd, uint32_t u32PhyAddr, void *pVirtAddr)
{
     int32_t ret = 0;
    MppBufferInfo bufferInfo = {0};

 //handle
 //fd
 //ptr

    return ret;
}
